package emby;

import java.io.File;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Scanner;

import emby.err.EmbyError;
import emby.err.InvalidArgumentError;
import emby.lang.EmbyNull;
import emby.lang.JavaMethodWrapper;
import emby.lang.Scope;
import emby.lang.stdlib.DefaultFunctions;
import emby.overload.OverloadCallable;
import emby.util.ReflectionHelp;

public class InteractiveTester {
	public static void main(String[] args) {
		InteractiveTester t = new InteractiveTester(System.err);
		t.interact();
	}

	private Scope scope;
	ArrayList<String> imports;
	PrintStream logStream;
	
	public InteractiveTester(){
		this(null);
	}
	
	public InteractiveTester(OutputStream log){
		imports = new ArrayList<String>();
		scope = new Scope();
		scope.setVar("peekFields", new PeekFields());
		scope.setVar("peekMethods", new PeekMethods());
		scope.setVar("jnew", DefaultFunctions.jnew);
		if( log != null){
			logStream = new PrintStream(log);
		}
	}
	
	public void interact(){
		Scanner s = new Scanner(System.in);
		System.out.println("Starting Emby Interactive Tester.");
		System.out.println("Type '--exit' to quit");	
		System.out.print(">>>");
		while( s.hasNext()){
			String code = s.nextLine();
			if( code.equals("--exit")){
				break;
			}
			Object result = null;
			try{
				result = eval(code);
			}catch(Exception e){
	        	e.printStackTrace();
			}
			if(!( (result == null) || (result == EmbyNull.Null))){
				System.out.println(result);
			}
			System.out.print(">>>");		
		}
	}
	
	public void imprt(String pkg){
		imports.add(pkg);
	}
	
	public Object eval(String code){
		if( logStream != null){
			logStream.println(code);
		}
		return Script.eval(code,scope);
	}
}

class PeekFields implements OverloadCallable{
	@Override
	public Object execute(int lineNumber, Scope s, Object... args) {
		// TODO Auto-generated method stub
		if( args.length != 1){
			throw new InvalidArgumentError(lineNumber, "PeekFields requires 1 argument");
		}
		Object obj = args[0];
		ArrayList<Field> flds = ReflectionHelp.getAllFields(obj.getClass());
		ArrayList<Object> vals = new ArrayList<Object>();
		int i=0;
		for( Field f : flds){
			try {
				Object o = f.get(obj);
				vals.add(o);
				EmbyRuntime.out.printf("%d %s : ",i,f.toGenericString());
				EmbyRuntime.out.println(o);
				i++;
			} catch (IllegalArgumentException e) {
				//EmbyRuntime.out.println("<Inaccessible>");
			} catch (IllegalAccessException e) {
				//EmbyRuntime.out.println("<Inaccessible>");
			}
		}
		if( i==0){
			EmbyRuntime.out.println("No readable fields");		
		}
		return vals;
	}
}

class PeekMethods implements OverloadCallable{

	@Override
	public Object execute(int lineNumber, Scope s, Object... args) {
		if( args.length != 1){
			throw new InvalidArgumentError(lineNumber, "PeekMethods requires 1 argument");
		}
		Object obj = args[0];
		ArrayList<Method> mthd = ReflectionHelp.getAllMethods(obj.getClass());
		ArrayList<Object> vals = new ArrayList<Object>();
		int i=0;
		for( Method m : mthd){
			try {
				Method[] m_ = {m};
				vals.add(new JavaMethodWrapper(obj,m_));
				EmbyRuntime.out.printf("%d %s\n",i,m);
				i++;
			} catch (IllegalArgumentException e) {
				//EmbyRuntime.out.println("<Inaccessible>");
			}
		}
		// TODO Auto-generated method stub
		return vals;
	}
}
